<template>
  <div class="min-h-screen bg-gradient-to-br from-green-50 to-yellow-50 py-8">
    <div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
      <div class="flex flex-col lg:flex-row gap-6">
        <main class="flex-1 bg-white p-6 rounded-lg shadow">
          <h1 class="text-2xl font-bold mb-2">拉弓射箭小游戏</h1>
          <p class="text-sm text-gray-600 mb-4">按住并向后拖动拉弓，松开发射。共 5 次机会。五环对应分数：10 / 8 / 6 / 4 / 2，靶外 0 分。</p>

          <div class="flex flex-col lg:flex-row gap-6">
            <div class="flex-1 flex flex-col items-center">
              <div class="mb-3">第 {{ shots.length + 1 }} 次射击（共 5 次）</div>

              <div class="bg-white p-4 rounded-lg shadow">
                <svg ref="svgEl" :width="size" :height="size" class="touch-none" @pointerdown="onPointerDown" @pointermove="onPointerMove" @pointerup="onPointerUp" @pointercancel="onPointerUp">
                  <!-- background circle area -->
                  <rect x="0" y="0" :width="size" :height="size" fill="#f8fafc" />

                  <!-- target rings -->
                  <circle :cx="center" :cy="center" :r="radius" fill="#f8fafc" stroke="#e5e7eb" />
                  <circle :cx="center" :cy="center" :r="ringRadii[4]" :fill="ringColors[4]" stroke="#ddd" />
                  <circle :cx="center" :cy="center" :r="ringRadii[3]" :fill="ringColors[3]" stroke="#ddd" />
                  <circle :cx="center" :cy="center" :r="ringRadii[2]" :fill="ringColors[2]" stroke="#ddd" />
                  <circle :cx="center" :cy="center" :r="ringRadii[1]" :fill="ringColors[1]" stroke="#ddd" />
                  <circle :cx="center" :cy="center" :r="ringRadii[0]" :fill="ringColors[0]" stroke="#ccc" />

                  <!-- center crosshair -->
                  <line :x1="center-6" :y1="center" :x2="center+6" :y2="center" stroke="#333" stroke-width="1" />
                  <line :x1="center" :y1="center-6" :x2="center" :y2="center+6" stroke="#333" stroke-width="1" />

                  <!-- bow at bottom center -->
                  <g>
                    <line :x1="bow.x" :y1="bow.y-30" :x2="bow.x" :y2="bow.y+30" stroke="#6b7280" stroke-width="3" stroke-linecap="round" />
                    <!-- bow curve -->
                    <path :d="bowPath" stroke="#92400e" stroke-width="4" fill="none" stroke-linecap="round" />
                  </g>

                  <!-- string (when dragging) -->
                  <line v-if="isDragging" :x1="bow.x" :y1="bow.y" :x2="dragPoint.x" :y2="dragPoint.y" stroke="#4b5563" stroke-width="2" />

                  <!-- arrow (static at bow when idle or during drag) -->
                  <g :transform="`translate(${arrowPos.x},${arrowPos.y}) rotate(${arrowAngleDeg})`">
                    <rect x="-18" y="-3" width="24" height="6" rx="2" fill="#374151" />
                    <polygon points="6,-6 12,0 6,6" fill="#111827" />
                  </g>

                  <!-- flying arrow (during animation) -->
                  <g v-if="flying.visible" :transform="`translate(${flying.x},${flying.y}) rotate(${flying.angle})`">
                    <rect x="-18" y="-3" width="24" height="6" rx="2" fill="#ef4444" />
                    <polygon points="6,-6 12,0 6,6" fill="#7f1d1d" />
                  </g>

                  <!-- show hits -->
                  <g v-for="(h, i) in hits" :key="i">
                    <circle :cx="h.x" :cy="h.y" r="6" fill="rgba(255,0,0,0.9)" stroke="#fff" stroke-width="1" />
                  </g>
                </svg>
              </div>

              <div class="mt-4 w-full text-center">
                <div class="text-lg font-semibold">当前得分：{{ total }}</div>
                <div class="text-sm text-gray-500">已射 {{ shots.length }} / 5 次</div>
              </div>

              <div class="flex items-center gap-3 mt-4">
                <button class="px-4 py-2 bg-indigo-600 text-white rounded" @click="reset">重置</button>
                <input v-model="name" placeholder="你的名字（用于排行榜，可选）" class="border rounded px-2 py-1" />
                <button :disabled="shots.length < 5 || submitting" class="px-3 py-1 bg-green-500 text-white rounded disabled:opacity-60" @click="submitScore">保存成绩</button>
              </div>
            </div>

            <aside class="w-full lg:w-80 bg-white p-4 rounded-lg shadow max-h-[520px] overflow-hidden">
              <h2 class="text-lg font-semibold mb-3">排行榜（最近 7 天）</h2>
              <div class="text-xs text-gray-500 mb-2">按总分降序（越高越好）。</div>

              <div ref="listEl" class="overflow-y-auto" style="max-height:420px">
                <ul>
                  <li v-for="(item, idx) in leaderboard" :key="item.id" class="py-2 px-2 border-b last:border-b-0 flex items-center justify-between">
                    <div class="flex items-center gap-3">
                      <div class="w-8 text-center">{{ idx + 1 }}</div>
                      <div>
                        <div class="font-medium">{{ item.name || '匿名' }}</div>
                        <div class="text-xs text-gray-500">{{ new Date(item.ts).toLocaleString() }}</div>
                      </div>
                    </div>
                    <div class="text-right">
                      <div class="font-semibold">{{ item.score }} 分</div>
                      <div v-if="idx===0" class="text-xs text-red-500">第一名</div>
                    </div>
                  </li>
                </ul>
                <div v-if="leaderboard.length===0" class="text-center text-gray-400 py-8">暂无成绩，快来挑战！</div>
              </div>
            </aside>
          </div>
        </main>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, computed } from 'vue'

const size = 360
const center = size / 2
const radius = 140
const ringCount = 5
const ringColors = ['#fee2e2','#fca5a5','#fb923c','#f97316','#f59e0b'] // inner -> outer (lighter inner)
const ringRadii = []
for (let i = 0; i < ringCount; i++) {
  ringRadii[i] = (radius / ringCount) * (ringCount - i)
}

const bow = { x: center, y: size - 30 }

const shots = ref([])
const hits = ref([])
const name = ref('')
const leaderboard = ref([])
const submitting = ref(false)

const isDragging = ref(false)
const dragPoint = ref({ x: bow.x, y: bow.y })
const arrowPos = ref({ x: bow.x, y: bow.y })
const arrowAngleDeg = ref(0)

const flying = ref({ visible: false, x: 0, y: 0, vx: 0, vy: 0, angle: 0 })

const scoresMap = [10,8,6,4,2]

const total = computed(() => shots.value.reduce((s, v) => s + v, 0))

const fetchLeaderboard = async (limit = 50) => {
  try {
    const res = await $fetch('/api/archery/list?limit=' + limit)
    if (Array.isArray(res)) {
      leaderboard.value = res.map((r) => ({ ...r }))
    }
  } catch (err) {
    // ignore
  }
}

// bow path (simple curve) computed property
const bowPath = `M ${bow.x - 20} ${bow.y - 30} q 20 30 40 0`

const onPointerDown = (e) => {
  if (shots.value.length >= 5) return
  isDragging.value = true
  const rect = e.currentTarget.getBoundingClientRect()
  const x = e.clientX - rect.left
  const y = e.clientY - rect.top
  dragPoint.value = { x, y }
  updateArrowOrientation(x, y)
  // capture pointer for continued move events
  if (e.currentTarget && e.currentTarget.setPointerCapture) {
    try { e.currentTarget.setPointerCapture(e.pointerId) } catch (err) {}
  }
}

const onPointerMove = (e) => {
  if (!isDragging.value) return
  const rect = e.currentTarget.getBoundingClientRect()
  const x = e.clientX - rect.left
  const y = e.clientY - rect.top
  dragPoint.value = { x, y }
  // arrow drawn at bow but rotate to shot direction (from drag -> bow)
  updateArrowOrientation(x, y)
}

const onPointerUp = (e) => {
  if (!isDragging.value) return
  isDragging.value = false
  const rect = e.currentTarget.getBoundingClientRect()
  const x = e.clientX - rect.left
  const y = e.clientY - rect.top
  dragPoint.value = { x, y }
  // compute shot
  shootFromDrag(x, y)
  try { if (e.currentTarget && e.currentTarget.releasePointerCapture) { e.currentTarget.releasePointerCapture(e.pointerId) } } catch (err) {}
}

const updateArrowOrientation = (x, y) => {
  // shot direction is from drag point toward bow (pulling back), so arrow points opposite
  const dx = bow.x - x
  const dy = bow.y - y
  const ang = Math.atan2(dy, dx)
  arrowAngleDeg.value = (ang * 180) / Math.PI
}

const shootFromDrag = (x, y) => {
  // compute pull distance
  const dx = bow.x - x
  const dy = bow.y - y
  const dist = Math.sqrt(dx*dx + dy*dy)
  const maxPull = 120
  const pull = Math.min(dist, maxPull)
  const power = pull / maxPull // 0..1

  // shot direction normalized
  const dirx = dx / (dist || 1)
  const diry = dy / (dist || 1)

  // compute final landing point relative to bow
  const travel = radius * 1.4 * (0.5 + power * 1.5) // scale to allow hitting target
  const finalX = bow.x + dirx * travel
  const finalY = bow.y + diry * travel

  // animate arrow from bow to final point
  animateArrowTo(finalX, finalY, dirx, diry, () => {
    // determine score based on distance to center
    const dxC = finalX - center
    const dyC = finalY - center
    const distC = Math.sqrt(dxC*dxC + dyC*dyC)
    const ringWidth = radius / ringCount
    const idx = Math.floor(distC / ringWidth)
    let sc = 0
    if (idx < ringCount) sc = scoresMap[idx]
    shots.value.push(sc)
    hits.value.push({ x: finalX, y: finalY })
    // reset arrow static pos
    arrowPos.value = { x: bow.x, y: bow.y }
    arrowAngleDeg.value = 0
  })
}

const animateArrowTo = (tx, ty, dirx, diry, cb) => {
  flying.value.visible = true
  flying.value.x = bow.x
  flying.value.y = bow.y
  flying.value.angle = arrowAngleDeg.value
  const duration = 500
  const start = performance.now()
  const sx = bow.x, sy = bow.y

  const frame = (t) => {
    const p = Math.min(1, (t - start) / duration)
    // ease out
    const ease = 1 - Math.pow(1 - p, 3)
    flying.value.x = sx + (tx - sx) * ease
    flying.value.y = sy + (ty - sy) * ease
    flying.value.angle = arrowAngleDeg.value
    if (p < 1) {
      requestAnimationFrame(frame)
    } else {
      // finalize
      flying.value.visible = false
      cb && cb()
    }
  }
  requestAnimationFrame(frame)
}

const reset = () => {
  shots.value = []
  hits.value = []
  arrowPos.value = { x: bow.x, y: bow.y }
  arrowAngleDeg.value = 0
}

const submitScore = async () => {
  if (shots.value.length < 5) {
    alert('请完成 5 次射击后再保存')
    return
  }
  submitting.value = true
  try {
    await $fetch('/api/archery/submit', { method: 'POST', body: { name: name.value || '匿名', score: total.value } })
    await fetchLeaderboard(50)
    alert('成绩已保存到排行榜')
  } catch (err) {
    alert('保存失败: ' + String(err))
  } finally {
    submitting.value = false
  }
}

onMounted(async () => {
  await fetchLeaderboard()
})
</script>

<style scoped>
svg { max-width: 100%; height: auto; display: block }
</style>
